package org.jivesoftware.smack.util;

import java.io.PrintStream;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.jivesoftware.smack.util.collections.AbstractMapEntry;

public class Cache<K, V>
  implements Map<K, V>
{
  protected Map<K, CacheObject<V>> map;
  protected LinkedList lastAccessedList;
  protected LinkedList ageList;
  protected int maxCacheSize;
  protected long maxLifetime;
  protected long cacheHits;
  protected long cacheMisses = 0L;

  public Cache(int paramInt, long paramLong)
  {
    if (paramInt == 0)
      throw new IllegalArgumentException("Max cache size cannot be 0.");
    this.maxCacheSize = paramInt;
    this.maxLifetime = paramLong;
    this.map = new HashMap(103);
    this.lastAccessedList = new LinkedList();
    this.ageList = new LinkedList();
  }

  public synchronized V put(K paramK, V paramV)
  {
    Object localObject = null;
    if (this.map.containsKey(paramK))
      localObject = remove(paramK, true);
    CacheObject localCacheObject = new CacheObject(paramV);
    this.map.put(paramK, localCacheObject);
    localCacheObject.lastAccessedListNode = this.lastAccessedList.addFirst(paramK);
    LinkedListNode localLinkedListNode = this.ageList.addFirst(paramK);
    localLinkedListNode.timestamp = System.currentTimeMillis();
    localCacheObject.ageListNode = localLinkedListNode;
    cullCache();
    return localObject;
  }

  public synchronized V get(Object paramObject)
  {
    deleteExpiredEntries();
    CacheObject localCacheObject = (CacheObject)this.map.get(paramObject);
    if (localCacheObject == null)
    {
      this.cacheMisses += 1L;
      return null;
    }
    localCacheObject.lastAccessedListNode.remove();
    this.lastAccessedList.addFirst(localCacheObject.lastAccessedListNode);
    this.cacheHits += 1L;
    localCacheObject.readCount += 1;
    return localCacheObject.object;
  }

  public synchronized V remove(Object paramObject)
  {
    return remove(paramObject, false);
  }

  public synchronized V remove(Object paramObject, boolean paramBoolean)
  {
    CacheObject localCacheObject = (CacheObject)this.map.remove(paramObject);
    if (localCacheObject == null)
      return null;
    localCacheObject.lastAccessedListNode.remove();
    localCacheObject.ageListNode.remove();
    localCacheObject.ageListNode = null;
    localCacheObject.lastAccessedListNode = null;
    return localCacheObject.object;
  }

  public synchronized void clear()
  {
    Object[] arrayOfObject1 = this.map.keySet().toArray();
    for (Object localObject : arrayOfObject1)
      remove(localObject);
    this.map.clear();
    this.lastAccessedList.clear();
    this.ageList.clear();
    this.cacheHits = 0L;
    this.cacheMisses = 0L;
  }

  public synchronized int size()
  {
    deleteExpiredEntries();
    return this.map.size();
  }

  public synchronized boolean isEmpty()
  {
    deleteExpiredEntries();
    return this.map.isEmpty();
  }

  public synchronized Collection<V> values()
  {
    deleteExpiredEntries();
    return Collections.unmodifiableCollection(new AbstractCollection()
    {
      Collection<Cache.CacheObject<V>> values = Cache.this.map.values();

      public Iterator<V> iterator()
      {
        return new Iterator()
        {
          Iterator<Cache.CacheObject<V>> it = Cache.1.this.values.iterator();

          public boolean hasNext()
          {
            return this.it.hasNext();
          }

          public V next()
          {
            return ((Cache.CacheObject)this.it.next()).object;
          }

          public void remove()
          {
            this.it.remove();
          }
        };
      }

      public int size()
      {
        return this.values.size();
      }
    });
  }

  public synchronized boolean containsKey(Object paramObject)
  {
    deleteExpiredEntries();
    return this.map.containsKey(paramObject);
  }

  public void putAll(Map<? extends K, ? extends V> paramMap)
  {
    Iterator localIterator = paramMap.entrySet().iterator();
    while (localIterator.hasNext())
    {
      Map.Entry localEntry = (Map.Entry)localIterator.next();
      Object localObject = localEntry.getValue();
      if ((localObject instanceof CacheObject))
        localObject = ((CacheObject)localObject).object;
      put(localEntry.getKey(), localObject);
    }
  }

  public synchronized boolean containsValue(Object paramObject)
  {
    deleteExpiredEntries();
    CacheObject localCacheObject = new CacheObject(paramObject);
    return this.map.containsValue(localCacheObject);
  }

  public synchronized Set<Map.Entry<K, V>> entrySet()
  {
    deleteExpiredEntries();
    return new AbstractSet()
    {
      private final Set<Map.Entry<K, Cache.CacheObject<V>>> set = Cache.this.map.entrySet();

      public Iterator<Map.Entry<K, V>> iterator()
      {
        return new Iterator()
        {
          private final Iterator<Map.Entry<K, Cache.CacheObject<V>>> it = Cache.2.this.set.iterator();

          public boolean hasNext()
          {
            return this.it.hasNext();
          }

          public Map.Entry<K, V> next()
          {
            Map.Entry localEntry = (Map.Entry)this.it.next();
            return new AbstractMapEntry(localEntry.getKey(), ((Cache.CacheObject)localEntry.getValue()).object)
            {
              public V setValue(V paramAnonymous3V)
              {
                throw new UnsupportedOperationException("Cannot set");
              }
            };
          }

          public void remove()
          {
            this.it.remove();
          }
        };
      }

      public int size()
      {
        return this.set.size();
      }
    };
  }

  public synchronized Set<K> keySet()
  {
    deleteExpiredEntries();
    return Collections.unmodifiableSet(this.map.keySet());
  }

  public long getCacheHits()
  {
    return this.cacheHits;
  }

  public long getCacheMisses()
  {
    return this.cacheMisses;
  }

  public int getMaxCacheSize()
  {
    return this.maxCacheSize;
  }

  public synchronized void setMaxCacheSize(int paramInt)
  {
    this.maxCacheSize = paramInt;
    cullCache();
  }

  public long getMaxLifetime()
  {
    return this.maxLifetime;
  }

  public void setMaxLifetime(long paramLong)
  {
    this.maxLifetime = paramLong;
  }

  protected synchronized void deleteExpiredEntries()
  {
    if (this.maxLifetime <= 0L)
      return;
    LinkedListNode localLinkedListNode = this.ageList.getLast();
    if (localLinkedListNode == null)
      return;
    long l = System.currentTimeMillis() - this.maxLifetime;
    while (l > localLinkedListNode.timestamp)
    {
      if (remove(localLinkedListNode.object, true) == null)
      {
        System.err.println("Error attempting to remove(" + localLinkedListNode.object.toString() + ") - cacheObject not found in cache!");
        localLinkedListNode.remove();
      }
      localLinkedListNode = this.ageList.getLast();
      if (localLinkedListNode == null)
        return;
    }
  }

  protected synchronized void cullCache()
  {
    if (this.maxCacheSize < 0)
      return;
    if (this.map.size() > this.maxCacheSize)
    {
      deleteExpiredEntries();
      int i = (int)(this.maxCacheSize * 0.9D);
      for (int j = this.map.size(); j > i; j--)
        if (remove(this.lastAccessedList.getLast().object, true) == null)
        {
          System.err.println("Error attempting to cullCache with remove(" + this.lastAccessedList.getLast().object.toString() + ") - " + "cacheObject not found in cache!");
          this.lastAccessedList.getLast().remove();
        }
    }
  }

  private static class CacheObject<V>
  {
    public V object;
    public Cache.LinkedListNode lastAccessedListNode;
    public Cache.LinkedListNode ageListNode;
    public int readCount = 0;

    public CacheObject(V paramV)
    {
      this.object = paramV;
    }

    public boolean equals(Object paramObject)
    {
      if (this == paramObject)
        return true;
      if (!(paramObject instanceof CacheObject))
        return false;
      CacheObject localCacheObject = (CacheObject)paramObject;
      return this.object.equals(localCacheObject.object);
    }

    public int hashCode()
    {
      return this.object.hashCode();
    }
  }

  private static class LinkedList
  {
    private Cache.LinkedListNode head = new Cache.LinkedListNode("head", null, null);

    public LinkedList()
    {
      this.head.next = (this.head.previous = this.head);
    }

    public Cache.LinkedListNode getFirst()
    {
      Cache.LinkedListNode localLinkedListNode = this.head.next;
      if (localLinkedListNode == this.head)
        return null;
      return localLinkedListNode;
    }

    public Cache.LinkedListNode getLast()
    {
      Cache.LinkedListNode localLinkedListNode = this.head.previous;
      if (localLinkedListNode == this.head)
        return null;
      return localLinkedListNode;
    }

    public Cache.LinkedListNode addFirst(Cache.LinkedListNode paramLinkedListNode)
    {
      paramLinkedListNode.next = this.head.next;
      paramLinkedListNode.previous = this.head;
      paramLinkedListNode.previous.next = paramLinkedListNode;
      paramLinkedListNode.next.previous = paramLinkedListNode;
      return paramLinkedListNode;
    }

    public Cache.LinkedListNode addFirst(Object paramObject)
    {
      Cache.LinkedListNode localLinkedListNode = new Cache.LinkedListNode(paramObject, this.head.next, this.head);
      localLinkedListNode.previous.next = localLinkedListNode;
      localLinkedListNode.next.previous = localLinkedListNode;
      return localLinkedListNode;
    }

    public Cache.LinkedListNode addLast(Object paramObject)
    {
      Cache.LinkedListNode localLinkedListNode = new Cache.LinkedListNode(paramObject, this.head, this.head.previous);
      localLinkedListNode.previous.next = localLinkedListNode;
      localLinkedListNode.next.previous = localLinkedListNode;
      return localLinkedListNode;
    }

    public void clear()
    {
      for (Cache.LinkedListNode localLinkedListNode = getLast(); localLinkedListNode != null; localLinkedListNode = getLast())
        localLinkedListNode.remove();
      this.head.next = (this.head.previous = this.head);
    }

    public String toString()
    {
      Cache.LinkedListNode localLinkedListNode = this.head.next;
      StringBuilder localStringBuilder = new StringBuilder();
      while (localLinkedListNode != this.head)
      {
        localStringBuilder.append(localLinkedListNode.toString()).append(", ");
        localLinkedListNode = localLinkedListNode.next;
      }
      return localStringBuilder.toString();
    }
  }

  private static class LinkedListNode
  {
    public LinkedListNode previous;
    public LinkedListNode next;
    public Object object;
    public long timestamp;

    public LinkedListNode(Object paramObject, LinkedListNode paramLinkedListNode1, LinkedListNode paramLinkedListNode2)
    {
      this.object = paramObject;
      this.next = paramLinkedListNode1;
      this.previous = paramLinkedListNode2;
    }

    public void remove()
    {
      this.previous.next = this.next;
      this.next.previous = this.previous;
    }

    public String toString()
    {
      return this.object.toString();
    }
  }
}

/* Location:           D:\hygieia\userclient\common\libs\easemobchat_2.1.8.jar
 * Qualified Name:     org.jivesoftware.smack.util.Cache
 * JD-Core Version:    0.6.1
 */